home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / nt / ntunzip2.zip / CRYPT.C < prev    next >
C/C++ Source or Header  |  1994-01-08  |  27KB  |  866 lines

  1. /*
  2.    crypt.c (full version) by Info-ZIP.        Last revised:  8 Jan 94
  3.  
  4.    This code is not copyrighted and is put in the public domain.  The
  5.    encryption/decryption parts (as opposed to the non-echoing password
  6.    parts) were originally written in Europe; the whole file can there-
  7.    fore be freely distributed from any country except the USA.  If this
  8.    code is imported into the USA, it cannot be re-exported from from
  9.    there to another country.  (This restriction might seem curious, but
  10.    this is what US law requires.)
  11.  */
  12.  
  13. /* This encryption code is a direct transcription of the algorithm from
  14.    Roger Schlafly, described by Phil Katz in the file appnote.txt.  This
  15.    file (appnote.txt) is distributed with the PKZIP program (even in the
  16.    version without encryption capabilities).
  17.  */
  18.  
  19. #include "zip.h"
  20. #include "crypt.h"
  21.  
  22. #ifndef UNZIP         /* time.h already included in unzip's zip.h */
  23. #  include <time.h>
  24. #endif
  25.  
  26. #if (defined(DOS_NT_OS2) && !defined(__GO32__))
  27. #  include <process.h>
  28. #else
  29. #  if !defined(__386BSD__) && !defined(SYSV)  /* getpid() in unistd.h */
  30.      int  getpid OF((void));
  31. #  endif
  32. #endif
  33.  
  34. #ifndef __GNUC__
  35.    void srand OF((unsigned int));
  36. #endif
  37. int rand OF((void));
  38.  
  39. /* For now, assume DIRENT implies System V implies TERMIO */
  40. #if defined(DIRENT) || defined(SYSV)
  41. #  if !defined(NO_TERMIO) && !defined(TERMIO)
  42. #    define TERMIO
  43. #  endif
  44. #endif
  45.  
  46. #if (!defined(AMIGA) && !defined(MACOS))      /* (see crypt.h) */
  47. #  if (defined(DOS_NT_OS2) || defined(VMS))
  48. #    ifndef MSVMS
  49. #      define MSVMS
  50. #    endif
  51. #    ifdef DOS_NT_OS2
  52. #      ifdef __EMX__
  53. #        define getch() _read_kbd(0, 1, 0)
  54. #      else
  55. #        ifdef __GO32__
  56. #          include <pc.h>
  57. #          define getch() getkey()
  58. #        else /* !__GO32__ */
  59. #          include <conio.h>
  60. #        endif /* ?__GO32__ */
  61. #      endif
  62. #    else /* !DOS_NT_OS2 */
  63. #      ifdef PASSWD_FROM_STDIN
  64. #        define getch() getc(stdin)
  65. #      else
  66. #        define getch() getc(stderr)
  67. #      endif
  68. #      include <descrip.h>
  69. #      include <iodef.h>
  70. #      include <ttdef.h>
  71. #      if !defined(SS$_NORMAL)
  72. #        define SS$_NORMAL 1   /* only thing we need from <ssdef.h> */
  73. #      endif
  74. #    endif /* ?DOS_NT_OS2 */
  75. #  else /* !(DOS_NT_OS2 || VMS) */
  76. #    ifdef TERMIO       /* Amdahl, Cray, all SysV? */
  77. #      ifdef COHERENT
  78. #        include <termio.h>
  79. #      else
  80. #        ifdef LINUX
  81. #          include <termios.h>
  82. #        else
  83. #          include <sys/termio.h>
  84. #        endif
  85. #      endif /* ?COHERENT */
  86. #      define sgttyb termio
  87. #      define sg_flags c_lflag
  88. #      if !defined(__386BSD__) && !defined(SYSV)
  89.          int ioctl OF((int, int, voidp *)); /* already in unistd.h */
  90. #      endif
  91. #      define GTTY(f,s) ioctl(f,TCGETA,(voidp *)s)
  92. #      define STTY(f,s) ioctl(f,TCSETAW,(voidp *)s)
  93. #    else /* !TERMIO */
  94. #      if (!defined(MINIX) && !defined(__386BSD__))
  95. #        include <sys/ioctl.h>
  96. #      endif /* !MINIX && !__386BSD__ */
  97. #      include <sgtty.h>
  98. #      ifdef __386BSD__
  99. #        define GTTY(f, s) ioctl(f, TIOCGETP, (voidp *) s)
  100. #        define STTY(f, s) ioctl(f, TIOCSETP, (voidp *) s)
  101. #      else /* !__386BSD__ */
  102. #        define GTTY gtty
  103. #        define STTY stty
  104.          int gtty OF((int, struct sgttyb *));
  105.          int stty OF((int, struct sgttyb *));
  106. #      endif /* ?__386BSD__ */
  107. #    endif /* ?TERMIO */
  108. #    if defined(__386BSD__) || defined(SYSV) || defined(__convexc__)
  109. #      ifndef UNZIP
  110. #        include <fcntl.h>
  111. #      endif
  112. #    else
  113.        char *ttyname OF((int));
  114. #    endif
  115. #  endif /* ?(DOS_NT_OS2 || VMS) */
  116. #endif /* !AMIGA */
  117.  
  118. #ifdef UNZIP
  119.    char *key = (char *)NULL;  /* password with which to decrypt data, or NULL */
  120. #  ifndef FUNZIP
  121.      int newzip;              /* set TRUE in extract.c for each new zipfile */
  122.      local int testp OF((uch *h));
  123. #  endif
  124. #endif /* UNZIP */
  125.  
  126. local ulg keys[3]; /* keys defining the pseudo-random sequence */
  127.  
  128. #ifndef Trace
  129. #  ifdef CRYPT_DEBUG
  130. #    define Trace(x) fprintf x
  131. #  else
  132. #    define Trace(x)
  133. #  endif
  134. #endif
  135.  
  136. /***********************************************************************
  137.  * Return the next byte in the pseudo-random sequence
  138.  */
  139. int decrypt_byte()
  140. {
  141.    ush temp;
  142.  
  143.    temp = (ush)keys[2] | 2;
  144.    return (int)(((ush)(temp * (temp ^ 1)) >> 8) & 0xff);
  145. }
  146.  
  147. /***********************************************************************
  148.  * Update the encryption keys with the next byte of plain text
  149.  */
  150. int update_keys(c)
  151.     int c;                  /* byte of plain text */
  152. {
  153.     keys[0] = CRC32(keys[0], c);
  154.     keys[1] += keys[0] & 0xff;
  155.     keys[1] = keys[1] * 134775813L + 1;
  156.     keys[2] = CRC32(keys[2], (int)(keys[1] >> 24));
  157.     return c;
  158. }
  159.  
  160.  
  161. /***********************************************************************
  162.  * Initialize the encryption keys and the random header according to
  163.  * the given password.
  164.  */
  165. void init_keys(passwd)
  166.     char *passwd;             /* password string with which to modify keys */
  167. {
  168.     keys[0] = 305419896L;
  169.     keys[1] = 591751049L;
  170.     keys[2] = 878082192L;
  171.     while (*passwd != '\0') {
  172.         update_keys((int)*passwd);
  173.         passwd++;
  174.     }
  175. }
  176.  
  177. /***********************************************************************
  178.  * Write encryption header to file zfile using the password passwd
  179.  * and the cyclic redundancy check crc.
  180.  */
  181. void crypthead(passwd, crc, zfile)
  182.     char *passwd;                /* password string */
  183.     ulg crc;                     /* crc of file being encrypted */
  184.     FILE *zfile;                 /* where to write header */
  185. {
  186.     int n;                       /* index in random header */
  187.     int t;                       /* temporary */
  188.     int c;                       /* random byte */
  189.     int ztemp;                   /* temporary for zencoded value */
  190.     uch header[RAND_HEAD_LEN-2]; /* random header */
  191.     static unsigned calls = 0;   /* ensure different random header each time */
  192.  
  193.     /* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the
  194.      * output of rand() to get less predictability, since rand() is
  195.      * often poorly implemented.
  196.      */
  197.     if (++calls == 1) {
  198.         srand((unsigned)time(NULL) ^ getpid());
  199.     }
  200.     init_keys(passwd);
  201.     for (n = 0; n < RAND_HEAD_LEN-2; n++) {
  202.         c = (rand() >> 7) & 0xff;
  203.         header[n] = (uch)zencode(c, t);
  204.     }
  205.     /* Encrypt random header (last two bytes is high word of crc) */
  206.     init_keys(passwd);
  207.     for (n = 0; n < RAND_HEAD_LEN-2; n++) {
  208.         ztemp = zencode(header[n], t);
  209.         putc(ztemp, zfile);
  210.     }
  211.     ztemp = zencode((int)(crc >> 16) & 0xff, t);
  212.     putc(ztemp, zfile);
  213.     ztemp = zencode((int)(crc >> 24) & 0xff, t);
  214.     putc(ztemp, zfile);
  215. }
  216.  
  217.  
  218. #ifdef UTIL
  219.  
  220. /***********************************************************************
  221.  * Encrypt the zip entry described by z from file source to file dest
  222.  * using the password passwd.  Return an error code in the ZE_ class.
  223.  */
  224. int zipcloak(z, source, dest, passwd)
  225.     struct zlist far *z;    /* zip entry to encrypt */
  226.     FILE *source, *dest;    /* source and destination files */
  227.     char *passwd;           /* password string */
  228. {
  229.     int c;                  /* input byte */
  230.     int res;                /* result code */
  231.     ulg n;                  /* holds offset and counts size */
  232.     ush flag;               /* previous flags */
  233.     int t;                  /* temporary */
  234.     int ztemp;              /* temporary storage for zencode value */
  235.  
  236.     /* Set encrypted bit, clear extended local header bit and write local
  237.        header to output file */
  238.     if ((n = ftell(dest)) == -1L) return ZE_TEMP;
  239.     z->off = n;
  240.     flag = z->flg;
  241.     z->flg |= 1,  z->flg &= ~8;
  242.     z->lflg |= 1, z->lflg &= ~8;
  243.     z->siz += RAND_HEAD_LEN;
  244.     if ((res = putlocal(z, dest)) != ZE_OK) return res;
  245.  
  246.     /* Initialize keys with password and write random header */
  247.     crypthead(passwd, z->crc, dest);
  248.  
  249.     /* Skip local header in input file */
  250.     if (fseek(source, (long)(4 + LOCHEAD + (ulg)z->nam + (ulg)z->ext),
  251.               SEEK_CUR)) {
  252.         return ferror(source) ? ZE_READ : ZE_EOF;
  253.     }
  254.  
  255.     /* Encrypt data */
  256.     for (n = z->siz - RAND_HEAD_LEN; n; n--) {
  257.         if ((c = getc(source)) == EOF) {
  258.             return ferror(source) ? ZE_READ : ZE_EOF;
  259.         }
  260.         ztemp = zencode(c, t);
  261.         putc(ztemp, dest);
  262.     }
  263.     /* Skip extended local header in input file if there is one */
  264.     if ((flag & 8) != 0 && fseek(source, 16L, SEEK_CUR)) {
  265.         return ferror(source) ? ZE_READ : ZE_EOF;
  266.     }
  267.     if (fflush(dest) == EOF) return ZE_TEMP;
  268.     return ZE_OK;
  269. }
  270.  
  271. /***********************************************************************
  272.  * Decrypt the zip entry described by z from file source to file dest
  273.  * using the password passwd.  Return an error code in the ZE_ class.
  274.  */
  275. int zipbare(z, source, dest, passwd)
  276.     struct zlist far *z;  /* zip entry to encrypt */
  277.     FILE *source, *dest;  /* source and destination files */
  278.     char *passwd;         /* password string */
  279. {
  280.     int c0, c1;           /* last two input bytes */
  281.     ulg offset;           /* used for file offsets */
  282.     ulg size;             /* size of input data */
  283.     int r;                /* size of encryption header */
  284.     int res;              /* return code */
  285.     ush flag;             /* previous flags */
  286.  
  287.     /* Save position and skip local header in input file */
  288.     if ((offset = ftell(source)) == -1L ||
  289.         fseek(source, (long)(4 + LOCHEAD + (ulg)z->nam + (ulg)z->ext),
  290.               SEEK_CUR)) {
  291.         return ferror(source) ? ZE_READ : ZE_EOF;
  292.     }
  293.     /* Initialize keys with password */
  294.     init_keys(passwd);
  295.  
  296.     /* Decrypt encryption header, save last two bytes */
  297.     c1 = 0;
  298.     for (r = RAND_HEAD_LEN; r; r--) {
  299.         c0 = c1;
  300.         if ((c1 = getc(source)) == EOF) {
  301.             return ferror(source) ? ZE_READ : ZE_EOF;
  302.         }
  303.         Trace((stdout, " (%02x)", c1));
  304.         zdecode(c1);
  305.         Trace((stdout, " %02x", c1));
  306.     }
  307.     Trace((stdout, "\n"));
  308.  
  309.     /* If last two bytes of header don't match crc (or file time in the
  310.      * case of an extended local header), back up and just copy. For
  311.      * pkzip 2.0, the check has been reduced to one byte only.
  312.      */
  313. #ifdef ZIP10
  314.     if ((ush)(c0 | (c1<<8)) !=
  315.         (z->flg & 8 ? (ush) z->tim & 0xffff : (ush)(z->crc >> 16))) {
  316. #else
  317.     c0++; /* avoid warning on unused variable */
  318.     if ((ush)c1 != (z->flg & 8 ? (ush) z->tim >> 8 : (ush)(z->crc >> 24))) {
  319. #endif
  320.         if (fseek(source, offset, SEEK_SET)) {
  321.             return ferror(source) ? ZE_READ : ZE_EOF;
  322.         }
  323.         if ((res = zipcopy(z, source, dest)) != ZE_OK) return res;
  324.         return ZE_MISS;
  325.     }
  326.  
  327.     /* Clear encrypted bit and local header bit, and write local header to
  328.        output file */
  329.     if ((offset = ftell(dest)) == -1L) return ZE_TEMP;
  330.     z->off = offset;
  331.     flag = z->flg;
  332.     z->flg &= ~9;
  333.     z->lflg &= ~9;
  334.     z->siz -= RAND_HEAD_LEN;
  335.     if ((res = putlocal(z, dest)) != ZE_OK) return res;
  336.  
  337.     /* Decrypt data */
  338.     for (size = z->siz; size; size--) {
  339.         if ((c1 = getc(source)) == EOF) {
  340.             return ferror(source) ? ZE_READ : ZE_EOF;
  341.         }
  342.         zdecode(c1);
  343.         putc(c1, dest);
  344.     }
  345.     /* Skip extended local header in input file if there is one */
  346.     if ((flag & 8) != 0 && fseek(source, 16L, SEEK_CUR)) {
  347.         return ferror(source) ? ZE_READ : ZE_EOF;
  348.     }
  349.     if (fflush(dest) == EOF) return ZE_TEMP;
  350.  
  351.     return ZE_OK;
  352. }
  353.  
  354.  
  355. #else /* !UTIL */
  356.  
  357. /***********************************************************************
  358.  * If requested, encrypt the data in buf, and in any case call fwrite()
  359.  * with the arguments to zfwrite().  Return what fwrite() returns.
  360.  */
  361. unsigned zfwrite(buf, item_size, nb, f)
  362.     voidp *buf;                /* data buffer */
  363.     extent item_size;          /* size of each item in bytes */
  364.     extent nb;                 /* number of items */
  365.     FILE *f;                   /* file to write to */
  366. {
  367.     int t;                    /* temporary */
  368.  
  369.     if (key != (char *)NULL) { /* key is the global password pointer */
  370.         ulg size;              /* buffer size */
  371.         char *p = (char*)buf;  /* steps through buffer */
  372.  
  373.         /* Encrypt data in buffer */
  374.         for (size = item_size*(ulg)nb; size != 0; p++, size--) {
  375.             *p = (char)zencode(*p, t);
  376.         }
  377.     }
  378.     /* Write the buffer out */
  379.     return fwrite(buf, item_size, nb, f);
  380. }
  381.  
  382. #endif /* ?UTIL */
  383.  
  384. #ifdef VMS
  385.  
  386. /***********************************************************************
  387.  * Turn keyboard echoing on or off (VMS).  Loosely based on VMSmunch.c
  388.  * and hence on Joe Meadows' file.c code.
  389.  */
  390. int echo(opt)
  391.     int opt;
  392. {
  393.     /*
  394.      * For VMS v5.x:
  395.      *   IO$_SENSEMODE/SETMODE info:  Programming, Vol. 7A, System Programming,
  396.      *     I/O User's: Part I, sec. 8.4.1.1, 8.4.3, 8.4.5, 8.6
  397.      *   sys$assign(), sys$qio() info:  Programming, Vol. 4B, System Services,
  398.      *     System Services Reference Manual, pp. sys-23, sys-379
  399.      *   fixed-length descriptor info:  Programming, Vol. 3, System Services,
  400.      *     Intro to System Routines, sec. 2.9.2
  401.      * GRR, 15 Aug 91
  402.      */
  403.  
  404.     static struct dsc$descriptor_s DevDesc =
  405.         {9, DSC$K_DTYPE_T, DSC$K_CLASS_S, "SYS$INPUT"};
  406.      /* {dsc$w_length, dsc$b_dtype, dsc$b_class, dsc$a_pointer}; */
  407.     static short           DevChan, iosb[4];
  408.     static long            i, status;
  409.     static unsigned long   oldmode[2], newmode[2];   /* each = 8 bytes */
  410.   
  411.  
  412.     /* assign a channel to standard input */
  413.     status = sys$assign(&DevDesc, &DevChan, 0, 0);
  414.     if (!(status & 1))
  415.         return status;
  416.  
  417.     /* use sys$qio and the IO$_SENSEMODE function to determine the current
  418.      * tty status (for password reading, could use IO$_READVBLK function
  419.      * instead, but echo on/off will be more general)
  420.      */
  421.     status = sys$qio(0, DevChan, IO$_SENSEMODE, &iosb, 0, 0,
  422.                      oldmode, 8, 0, 0, 0, 0);
  423.     if (!(status & 1))
  424.         return status;
  425.     status = iosb[0];
  426.     if (!(status & 1))
  427.         return status;
  428.  
  429.     /* copy old mode into new-mode buffer, then modify to be either NOECHO or
  430.      * ECHO (depending on function argument opt)
  431.      */
  432.     newmode[0] = oldmode[0];
  433.     newmode[1] = oldmode[1];
  434.     if (opt == 0)   /* off */
  435.         newmode[1] |= TT$M_NOECHO;                      /* set NOECHO bit */
  436.     else
  437.         newmode[1] &= ~((unsigned long) TT$M_NOECHO);   /* clear NOECHO bit */
  438.  
  439.     /* use the IO$_SETMODE function to change the tty status */
  440.     status = sys$qio(0, DevChan, IO$_SETMODE, &iosb, 0, 0,
  441.                      newmode, 8, 0, 0, 0, 0);
  442.     if (!(status & 1))
  443.         return status;
  444.     status = iosb[0];
  445.     if (!(status & 1))
  446.         return status;
  447.  
  448.     /* deassign the sys$input channel by way of clean-up */
  449.     status = sys$dassgn(DevChan);
  450.     if (!(status & 1))
  451.         return status;
  452.  
  453.     return SS$_NORMAL;   /* we be happy */
  454.  
  455. } /* end function echo() */
  456.  
  457.  
  458. #else /* !VMS */
  459. #if (!defined(DOS_NT_OS2) && !defined(AMIGA) && !defined(MACOS))
  460.  
  461. static int echofd=(-1);       /* file descriptor whose echo is off */
  462.  
  463. /***********************************************************************
  464.  * Turn echo off for file descriptor f.  Assumes that f is a tty device.
  465.  */
  466. void echoff(f)
  467.     int f;                    /* file descriptor for which to turn echo off */
  468. {
  469.     struct sgttyb sg;         /* tty device structure */
  470.  
  471.     echofd = f;
  472.     GTTY(f, &sg);             /* get settings */
  473.     sg.sg_flags &= ~ECHO;     /* turn echo off */
  474.     STTY(f, &sg);
  475. }
  476.  
  477. /***********************************************************************
  478.  * Turn echo back on for file descriptor echofd.
  479.  */
  480. void echon()
  481. {
  482.     struct sgttyb sg;         /* tty device structure */
  483.  
  484.     if (echofd != -1) {
  485.         GTTY(echofd, &sg);    /* get settings */
  486.         sg.sg_flags |= ECHO;  /* turn echo on */
  487.         STTY(echofd, &sg);
  488.         echofd = -1;
  489.     }
  490. }
  491.  
  492. #endif /* !(DOS_NT_OS2 || AMIGA || MACOS) */
  493. #endif /* ?VMS */
  494.  
  495. #ifdef AMIGA
  496.  
  497. /***********************************************************************
  498.  * Get a password of length n-1 or less into *p using the prompt *m.
  499.  * The entered password is not echoed. 
  500.  *
  501.  * On AMIGA, SAS/C 6.x provides raw console input via getch().  This is
  502.  * also available in SAS/C 5.10b, if the separately chargeable ANSI
  503.  * libraries are used.
  504.  *
  505.  * Aztec C provides functions set_raw() and set_con() which we use for
  506.  * echoff() and echon().
  507.  *
  508.  * Code for other compilers needs to provide routines or macros for
  509.  * echoff() and echon() to either send ACTION_SET_CONSOLE packets or
  510.  * provice "pseudo non-echo" input by setting the background and
  511.  * foreground colors the same.  Then, only spaces visibly echo.  This
  512.  * approach is the default in crypt.h.  Unfortunately, the cursor
  513.  * cannot be held stationary during input because the standard getc()
  514.  * and getchar() system routines buffer input until CR entered (due to
  515.  * the lack of switchable raw I/O).  This may be considered an
  516.  * advantage since it allows feedback for backspacing errors.
  517.  *
  518.  * Simulating true raw I/O on systems without getch() introduces
  519.  * undesirable complexity and overhead, so we'll live with this 
  520.  * simpler method for those compilers.  
  521.  */
  522. char *getp(m, p, n)
  523.  
  524.     char *m,*p;
  525.     int n;
  526. {
  527.     int i;
  528.     int c;
  529.  
  530.     fputs (m,stderr);                      /* display prompt and flush */
  531.     fflush(stderr);
  532.  
  533.     echoff(2);
  534.  
  535.     i = 0;
  536.     while ( i <= n ) {
  537.        c=getch();
  538.        if ( (c == '\n') || (c == '\r')) break;   /* until user hits CR */
  539.        if (c == 0x03) {  /* ^C in input */
  540.            Signal(FindTask(NULL), SIGBREAKF_CTRL_C);
  541.            break;
  542.        }
  543.        if (i < n) p[i++]=(char)c;                   /* truncate past n */
  544.     }
  545.  
  546.     ECHO_NEWLINE();
  547.     echon();
  548.  
  549.     i = (i<n) ? i : (n-1);
  550.     p[i]=0;                                        /* terminate string */
  551.     return p;
  552. }
  553.  
  554. #endif /* AMIGA */
  555.  
  556.  
  557.  
  558. #ifdef DOS_NT_OS2
  559.  
  560. char *getp(m, p, n)
  561.     char *m;                /* prompt for password */
  562.     char *p;                /* return value: line input */
  563.     int n;                  /* bytes available in p[] */
  564. {
  565.     char c;                 /* one-byte buffer for read() to use */
  566.     int i;                  /* number of characters input */
  567.     char *w;                /* warning on retry */
  568.  
  569.     /* get password */
  570.     w = "";
  571.     do {
  572.         fputs(w, stderr);   /* warning if back again */
  573.         fputs(m, stderr);   /* prompt */
  574.         fflush(stderr);
  575.         i = 0;
  576.         do {                /* read line, keeping n */
  577.             if ((c = (char)getch()) == '\r')
  578.                 c = '\n';
  579.             if (i < n)
  580.                 p[i++] = c;
  581.         } while (c != '\n');
  582.         putc('\n', stderr);  fflush(stderr);
  583.         w = "(line too long--try again)\n";
  584.     } while (p[i-1] != '\n');
  585.     p[i-1] = 0;               /* terminate at newline */
  586.  
  587.     /* return pointer to password */
  588.     return p;
  589. }
  590.  
  591. #endif /* DOS_NT_OS2 */
  592.  
  593.  
  594.  
  595. #ifdef MACOS
  596.  
  597. char *getp(m, p, n)
  598.     char *m;                /* prompt for password */
  599.     char *p;                /* return value: line input */
  600.     int n;                  /* bytes available in p[] */
  601. {
  602.     WindowPtr whichWindow;
  603.     EventRecord theEvent;
  604.     char c;                 /* one-byte buffer for read() to use */
  605.     int i;                  /* number of characters input */
  606.     char *w;                /* warning on retry */
  607.  
  608.     /* get password */
  609.     w = "";
  610.     do {
  611.         fputs(w, stderr);   /* warning if back again */
  612.         fputs(m, stderr);   /* prompt */
  613.         i = 0;
  614.         do {                /* read line, keeping n */
  615.             do {
  616.                 SystemTask();
  617.                 if (!GetNextEvent(everyEvent, &theEvent))
  618.                     theEvent.what = nullEvent;
  619.                 else {
  620.                     switch (theEvent.what) {
  621.                     case keyDown:
  622.                         c = theEvent.message & charCodeMask;
  623.                         break;
  624.                     case mouseDown:
  625.                         if (FindWindow(theEvent.where, &whichWindow) ==
  626.                             inSysWindow)
  627.                             SystemClick(&theEvent, whichWindow);
  628.                         break;
  629.                     case updateEvt:
  630. #ifdef UNZIP
  631.                         screenUpdate((WindowPtr)theEvent.message);
  632. #endif
  633.                         break;
  634.                     }
  635.                 }
  636.             } while (theEvent.what != keyDown);
  637.             if (i < n)
  638.                 p[i++] = c;
  639.         } while (c != '\r');
  640.         putc('\n', stderr);
  641.         w = "(line too long--try again)\n";
  642.     } while (p[i-1] != '\r');
  643.     p[i-1] = 0;               /* terminate at newline */
  644.  
  645.     /* return pointer to password */
  646.     return p;
  647. }
  648.  
  649. #endif /* MACOS */
  650.  
  651.  
  652.  
  653. #ifdef UNIX
  654.  
  655. char *getp(m, p, n)
  656.     char *m;                  /* prompt for password */
  657.     char *p;                  /* return value: line input */
  658.     int n;                    /* bytes available in p[] */
  659. {
  660.     char c;                   /* one-byte buffer for read() to use */
  661.     int i;                    /* number of characters input */
  662.     char *w;                  /* warning on retry */
  663.     int f;                    /* file descriptor for tty device */
  664.  
  665. #ifdef PASSWD_FROM_STDIN
  666.     /* Read from stdin. This is unsafe if the password is stored on disk. */
  667.     f = 0;
  668. #else
  669.     /* turn off echo on tty */
  670.     if (!isatty(2))
  671.         return NULL;          /* error if not tty */
  672.  
  673.     /* Convex C seems to want (char *) in front of ttyname:  compiler bug? */
  674.     if ((f = open((char *)ttyname(2), 0)) == -1)
  675.         return NULL;
  676. #endif
  677.     /* get password */
  678.     w = "";
  679.     do {
  680.         fputs(w, stderr);     /* warning if back again */
  681.         fputs(m, stderr);     /* prompt */
  682.         fflush(stderr);
  683.         i = 0;
  684.         echoff(f);
  685.         do {                  /* read line, keeping n */
  686.             read(f, &c, 1);
  687.             if (i < n)
  688.                 p[i++] = c;
  689.         } while (c != '\n');
  690.         echon();
  691.         putc('\n', stderr);  fflush(stderr);
  692.         w = "(line too long--try again)\n";
  693.     } while (p[i-1] != '\n');
  694.     p[i-1] = 0;               /* terminate at newline */
  695.  
  696. #ifndef PASSWD_FROM_STDIN
  697.     close(f);
  698. #endif
  699.     /* return pointer to password */
  700.     return p;
  701. }
  702.  
  703. #endif /* UNIX */
  704.  
  705. #ifdef VMS
  706.  
  707. char *getp(m, p, n)
  708.     char *m;                  /* prompt for password */
  709.     char *p;                  /* return value: line input */
  710.     int n;                    /* bytes available in p[] */
  711. {
  712.     char c;                   /* one-byte buffer for read() to use */
  713.     int i;                    /* number of characters input */
  714.     char *w;                  /* warning on retry */
  715.  
  716.     /* get password */
  717.     w = "";
  718.     do {
  719.         if (*w)               /* bug: VMS adds \n to NULL fputs (apparently) */
  720.             fputs(w, stderr); /* warning if back again */
  721.         fputs(m, stderr);     /* prompt */
  722.         fflush(stderr);
  723.         i = 0;
  724.         echoff(f);
  725.         do {                  /* read line, keeping n */
  726.             if ((c = (char)getch()) == '\r')
  727.                 c = '\n';
  728.             if (i < n)
  729.                 p[i++] = c;
  730.         } while (c != '\n');
  731.         echon();
  732.         putc('\n', stderr);  fflush(stderr);
  733.         w = "(line too long--try again)\n";
  734.     } while (p[i-1] != '\n');
  735.     p[i-1] = 0;               /* terminate at newline */
  736.  
  737.     /* return pointer to password */
  738.     return p;
  739. }
  740.  
  741. #endif /* VMS */
  742.  
  743.  
  744.  
  745. #if (defined(UNZIP) && !defined(FUNZIP))
  746.  
  747. /***********************************************************************
  748.  * Get the password and set up keys for current zipfile member.  Return
  749.  * PK_ class error.
  750.  */
  751. int decrypt()
  752. {
  753.     ush b;
  754.     int n, r;
  755.     static int nopwd=FALSE;
  756.     char *m, *prompt;
  757.     uch h[RAND_HEAD_LEN];
  758.  
  759.     Trace((stdout, "\n[incnt = %d]: ", incnt));
  760.  
  761.     /* get header once (turn off "encrypted" flag temporarily so we don't
  762.      * try to decrypt the same data twice) */
  763.     pInfo->encrypted = FALSE;
  764.     for (n = 0; n < RAND_HEAD_LEN; n++) {
  765.         b = NEXTBYTE;
  766.         h[n] = (uch)b;
  767.         Trace((stdout, " (%02x)", h[n]));
  768.     }
  769.     pInfo->encrypted = TRUE;
  770.  
  771.     if (newzip) {         /* this is first encrypted member in this zipfile */
  772.         newzip = FALSE;
  773.         if (key) {        /* get rid of previous zipfile's key */
  774.             free(key);
  775.             key = NULL;
  776.         }
  777.     }
  778.  
  779.     /* if have key already, test it; else allocate memory for it */
  780.     if (key) {
  781.         if (!testp(h))
  782.             return PK_COOL;   /* existing password OK (else prompt for new) */
  783.         else if (nopwd)
  784.             return PK_WARN;   /* user indicated no more prompting */
  785.     } else if ((key = (char *)malloc(PWLEN+1)) == (char *)NULL)
  786.         return PK_MEM2;
  787.  
  788.     if ((prompt = (char *)malloc(FILNAMSIZ+15)) != (char *)NULL) {
  789.         /* sprintf(prompt, "%s password: ", filename); */
  790.         sprintf(prompt, "[%s] %s password: ", zipfn, filename);
  791.         m = prompt;
  792.     } else
  793.         m = "Enter password: ";
  794.  
  795.     /* try a few keys */
  796.     for (r = 0;  r < 3;  ++r) {
  797.         m = getp(m, key, PWLEN+1);
  798.         if (prompt != (char *)NULL) {
  799.             free(prompt);
  800.             prompt = (char *)NULL;
  801.         }
  802.         if (m == (char *)NULL)
  803.             return PK_MEM2;
  804.         if (!testp(h))
  805.             return PK_COOL;
  806.         if (*key == '\0') {
  807.             nopwd = TRUE;
  808.             return PK_WARN;
  809.         }
  810.         m = "password incorrect--reenter: ";
  811.     }
  812.     return PK_WARN;
  813. } /* end function decrypt() */
  814.  
  815. /***********************************************************************
  816.  * Test the password.  Return -1 if bad, 0 if OK.
  817.  */
  818. local int testp(h)
  819.     uch *h;
  820. {
  821.     ush b, c;
  822.     int n;
  823.     uch *p;
  824.     uch hh[RAND_HEAD_LEN]; /* decrypted header */
  825.  
  826.     /* set keys and save the encrypted header */
  827.     init_keys(key);
  828.     memcpy(hh, h, RAND_HEAD_LEN);
  829.  
  830.     /* check password */
  831.     for (n = 0; n < RAND_HEAD_LEN; n++) {
  832.         zdecode(hh[n]);
  833.         Trace((stdout, " %02x", hh[n]));
  834.     }
  835.     c = hh[RAND_HEAD_LEN-2], b = hh[RAND_HEAD_LEN-1];
  836.  
  837.     Trace((stdout,
  838.       "\n  lrec.crc= %08lx  crec.crc= %08lx  pInfo->ExtLocHdr= %s\n",
  839.       lrec.crc32, pInfo->crc, pInfo->ExtLocHdr? "true":"false"));
  840.     Trace((stdout, "  incnt = %d  unzip offset into zipfile = %ld\n", incnt,
  841.       cur_zipfile_bufstart+(inptr-inbuf)));
  842.     Trace((stdout,
  843.       "  (c | (b<<8)) = %04x  (crc >> 16) = %04x  lrec.time = %04x\n",
  844.       (ush)(c | (b<<8)), (ush)(lrec.crc32 >> 16), lrec.last_mod_file_time));
  845.  
  846.     /* same test as in zipbare(): */
  847.  
  848. #ifdef ZIP10 /* check two bytes */
  849.     if ((ush)(c | (b<<8)) != (pInfo->ExtLocHdr? lrec.last_mod_file_time :
  850.         (ush)(lrec.crc32 >> 16)))
  851.         return -1;  /* bad */
  852. #else
  853.     c++; /* avoid warning on unused variable */
  854.     if (b != (pInfo->ExtLocHdr? lrec.last_mod_file_time >> 8 :
  855.         (ush)(lrec.crc32 >> 24)))
  856.         return -1;  /* bad */
  857. #endif
  858.     /* password OK:  decrypt current buffer contents before leaving */
  859.     for (n = (long)incnt > csize ? (int)csize : incnt, p = inptr; n--; p++)
  860.         zdecode(*p);
  861.     return 0;       /* OK */
  862.  
  863. } /* end function testp() */
  864.  
  865. #endif /* UNZIP && !FUNZIP */
  866.